//=====================================================================
// 文件名称：isr.c，中断处理源文件
// 提供者：SD-ARM，sumcu.suda.edu.cn
// 版本号：20210712
// 文件描述：提供中断处理函数
// 授权信息：商用
//=====================================================================

#include <main.h>
#define PTD_NUM    (3<<8)

// 设置CLINT计时器比较值
void clint_timer_cmp_set_val(int val);
// 读取当前计数器值
static inline uint64_t counter(void);

// GPIOD非安全中断处理函数
// void IRQ_GPIOD_NS_Handler(void) {
//     uint8_t flag = gpio_get_int(PTD_NUM | 10);
//     if (flag) {
//         printf("触发了GPIOD中断\n");
//     }
//     gpio_clear_int(PTD_NUM | 10);
// }

// // TIMER0中断处理函数
// void IRQ_TIMER0_Handler(void) {
//     uint8_t flag = timer_get_int(0);
//     static uint32_t count = 0;
//     if (flag) {
//         timer_clear_int(0);
//         count++;
//         printf("count=%d\r\n", count);
//     }
// }

// // UART2中断处理函数
// void IRQ_UART2_Hander(void) {
//     uint8_t flag, ch;
//     if (uart_get_re_int(2)) {
//         ch = uart_re1(2, &flag);
//         uart_send1(2, ch);
//     }
// }

// 默认处理程序
void defaultProgarm(void);
// 默认MTIME处理程序
void mtimedefault(void);
// 中断和异常处理函数
uint64_t handle_trap(uint64_t Mcause, uint64_t epc) {
    uint64_t MTVAL;
    if (Mcause & (1UL << 63)) {
        printf("enter if\n");
        unsigned long cause = Mcause & ~(1UL << 63);
        unsigned long pending = csr_read(mip) & (1 << cause);
        switch (cause) {
            case 0:     // 用户软件中断
            case 1:     // 监督软件中断
            case 2:     // 超管软件中断
            case 3:     // 机器软件中断
            case 4:     // 用户定时器中断
            case 5:     // 监督定时器中断
            case 6:     // 超管定时器中断
            case 7:     // 机器定时器中断
                csr_clear(mip, pending);
                clint_timer_cmp_set_val(24000000);
                break;
            case 8:     // 用户外部中断
            case 9:     // 监督外部中断
            case 10:    // 超管外部中断
            case 11:    // 机器外部中断
                csr_clear(mip, pending);
                system_irqhandler();
                break;
            default:
                break;
        }
    } else {
        printf("Mcause=%x\n", Mcause);
        switch (Mcause) {
            case 0x0:   // 不对齐的取指
            case 0x1:   // 取指访问异常
            case 0x2:   // 非法指令
            case 0x3:   // 断点
                defaultProgarm();
                break;
            case 0x4:   // 不对齐的加载
                defaultProgarm();
                break;
            case 0x5:   // 加载访问异常
                MTVAL = csr_read(mtval);
                printf("MTVAL=%x\n", MTVAL);
                break;
            case 0x6:   // 不对齐的存储
                defaultProgarm();
                break;
            case 0x7:   // 存储访问异常
            case 0x8:   // 用户级环境调用
            case 0x9:   // 监督级环境调用
            case 0xa:   // 超管级环境调用
            case 0xb:   // 机器级环境调用
                defaultProgarm();
                break;
            default:
                defaultProgarm();
                break;
        }
    }
    return epc;
}

// 默认程序
void defaultProgarm(void) {
    printf("defaultProgarm\n");
}

// 默认MTIME程序
void mtimedefault(void) {
    printf("mtimedefaultProgarm\n");
}

// 设置CLINT计时器比较值
void clint_timer_cmp_set_val(int val) {
    uint64_t val1;
    val1 = counter();
    printf("val1=%d\n", val1);
    *(uint64_t*)CLINT_MTIMECMPL(0) = counter() + val;
}

// 读取当前计数器值
static inline uint64_t counter(void) {
    uint64_t cnt;
    __asm__ __volatile__("csrr %0, time" : "=r"(cnt) :: "memory");
    return cnt;
}
